/*\
|*| chatabase JSON request 'client' tests
|*|
|*| suite-specific test fixures data is defined in prepareTestFixures()
|*| the main difference between the 'client' tests and the 'message' tests
|*|     is that the 'client' tests register a channel and require no authentication
|*|     but the 'message' tests require a valid client secret
|*| upon registration, a client secret is returned
|*|     to be used in combination with the canonical 'ROOM_NAME' name as authentication
|*|     so once the 'client' tests are run successfully
|*|     then there will be such a secret in the prim description for subsequent tests
|*| a single client should be created and persist for all subsequent tests
|*|     because clients can not exist with duplicate room names
|*|     and messages can not be deleted explicitly
|*|     any pre-existing test client in the db will be deleted via '/test_clients.json'
|*|     unless the special :nick => 'TEST_DUPS_NICKS' is present
\*/


// suite-specific test data
string  SUITE_NAME      = "clients" ;
string  RESOURCE_PATH   = "/test_clients.json" ;
string  TEST_DUPS_NICKS = "TEST_DUPS_NICKS" ;
string  DUPLICATES_RESP = "{\"secret\":\"exists\"}" ;
list    FIXTURES ;   // prepareTestFixures()
integer N_FIXTURES ; // prepareTestFixures()

// runtime switches
integer DEBUG_EVS = FALSE ;

// shared project-specific constants
string  GRID_NAME ;          // loadSharedData()
string  REGION_NAME ;        // loadSharedData()
string  PARCEL_NAME ;        // loadSharedData()
string  ROOM_NAME_SENTINAL ; // loadSharedData()
string  EXCEPTION_RESP ;     // loadSharedData()
string  SECRET_RESP ;        // loadSharedData()
string  OWNER_NAME ;         // loadSharedData()
string  ROOM_NAME ;          // loadSharedData()
integer GRID_IDX      = -1 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer REGION_IDX    = -2 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer PARCEL_IDX    = -3 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer SENTINEL_IDX  = -4 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer EXCEPTION_IDX = -5 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer SECRET_IDX    = -6 ; // ASSERT: negative int NOT DATA_LOAD_IDX
integer OWNER_IDX     = -7 ; // ASSERT: negative int NOT DATA_LOAD_IDX

// link messages
integer DATA_LOAD_IDX   = -420 ; // ASSERT: negative int
key     DATA_RETURN_EVT = "data" ;
integer N_PARAMS        = 4 ;
integer DESCRIPTION_IDX = 0 ; // ASSERT: FIXTURES strided index
integer REQUEST_IDX     = 1 ; // ASSERT: FIXTURES strided index
integer RESPONSE_IDX    = 2 ; // ASSERT: FIXTURES strided index
integer STATUS_IDX      = 3 ; // ASSERT: FIXTURES strided index
integer ENDPOINT_IDX    = 4 ;

// http status
integer HTTP_STATUS_SUCCESS  = 200 ;
integer HTTP_STATUS_BAD      = 400 ;
integer HTTP_STATUS_REJECTED = 420 ;


// runtime vars
integer IsInitialized = FALSE ;


/* state default functions */

integer loadSharedData(integer data_idx , string data)
{
  if (data == "") return FALSE ;

  if      (data_idx == GRID_IDX     ) GRID_NAME          = data ;
  else if (data_idx == REGION_IDX   ) REGION_NAME        = data ;
  else if (data_idx == PARCEL_IDX   ) PARCEL_NAME        = data ;
  else if (data_idx == SENTINEL_IDX ) ROOM_NAME_SENTINAL = data ;
  else if (data_idx == EXCEPTION_IDX) EXCEPTION_RESP     = data ;
  else if (data_idx == SECRET_IDX   ) SECRET_RESP        = data ;
  else if (data_idx == OWNER_IDX    ) OWNER_NAME         = data ;

  integer is_ready = GRID_NAME      != "" && REGION_NAME        != "" &&
                     PARCEL_NAME    != "" && ROOM_NAME_SENTINAL != "" &&
                     EXCEPTION_RESP != "" && EXCEPTION_RESP     != "" &&
                     EXCEPTION_RESP != "" && OWNER_NAME         != ""  ;

  if (is_ready)
    ROOM_NAME = llDumpList2String([ GRID_NAME , REGION_NAME , PARCEL_NAME ] , " ") ;

  return is_ready ;
}

prepareTestFixures()
{
  /* client creation schema
  {
    client:
    {
      room:   "GridName Region%20Name Parcel%20Name" ,
      nicks:  "FirstName LastName"                   ,
      type:   'SimClient'
    }
  }
  */


  /* fixture stride schema
  [
    test description       .
    outgoing request JSON  ,
    expected response JSON ,
    expected status
  ]
  */


  /* fixtures */

  FIXTURES =
  [
    "should not CREATE Client with missing Client params" ,
    "{}"                                                  ,
    EXCEPTION_RESP                                        ,
    HTTP_STATUS_BAD                                       ,

    "should not CREATE Client with empty Client params" ,
    "{ 'client': {} }"                                  ,
    EXCEPTION_RESP                                      ,
    HTTP_STATUS_BAD                                     ,

    "should not CREATE Client with missing room name"                                                          ,
    "{ 'client': {                               'nicks': '" + OWNER_NAME      + "' , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should not CREATE Client with missing nicks list"                                                         ,
    "{ 'client': { 'room': '" + ROOM_NAME + "'                                      , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should not CREATE Client with missing client type"                                                        ,
    "{ 'client': { 'room': '" + ROOM_NAME + "' , 'nicks': '" + OWNER_NAME      + "'                       } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should not CREATE Client with blank room name"                                                            ,
    "{ 'client': { 'room': ''                  , 'nicks': '" + OWNER_NAME      + "' , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should not CREATE Client with blank nicks list"                                                           ,
    "{ 'client': { 'room': '" + ROOM_NAME + "' , 'nicks': ''                        , 'type': 'SimClient' } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should not CREATE Client with blank client type"                                                          ,
    "{ 'client': { 'room': '" + ROOM_NAME + "' , 'nicks': '" + OWNER_NAME      + "' , 'type': ''          } }" ,
    EXCEPTION_RESP                                                                                             ,
    HTTP_STATUS_BAD                                                                                            ,

    "should CREATE Client with valid params"                                                                   ,
    "{ 'client': { 'room': '" + ROOM_NAME + "' , 'nicks': '" + OWNER_NAME      + "' , 'type': 'SimClient' } }" ,
    SECRET_RESP                                                                                                ,
    HTTP_STATUS_SUCCESS                                                                                        ,

    "should not CREATE Client with duplicate room name"                                                        ,
    "{ 'client': { 'room': '" + ROOM_NAME + "' , 'nicks': '" + TEST_DUPS_NICKS + "' , 'type': 'SimClient' } }" ,
    DUPLICATES_RESP                                                                                            ,
    HTTP_STATUS_REJECTED
  ] ;
  //list set_create_client_json = [ "room"  , ROOM_NAME , "nicks" , OWNER_NAME , "type"  , "SimClient" ] ;


  /* validation */

  if (llGetListLength(FIXTURES) % N_PARAMS) FIXTURES = [] ;
  N_FIXTURES = llGetListLength(FIXTURES) / N_PARAMS ;
}


/* helpers */

DBG_EVS(string msg) { if (DEBUG_EVS) llOwnerSay(msg) ; }

sendLinkMsg(integer data_idx , string data)
{
DBG_EVS("CLIENT::SEND    -> " + llList2CSV([DATA_RETURN_EVT , data_idx , data])) ;

  llMessageLinked(LINK_THIS , data_idx , data , DATA_RETURN_EVT) ;
}


default
{
  state_entry() { IsInitialized = FALSE ; }

  link_message(integer sender , integer data_idx , string data , key evt)
  {
    if (evt != SUITE_NAME) return ;

DBG_EVS("CLIENT::RECV    <- " + llList2CSV([evt , data_idx , data])) ;

    if (!loadSharedData(data_idx , data)) return ;

    IsInitialized = TRUE ; prepareTestFixures() ; state ready ;
  }
}

state ready
{
  state_entry() { sendLinkMsg(DATA_LOAD_IDX , (string)N_FIXTURES) ; }

  link_message(integer sender , integer test_n , string unused , key evt)
  {
    if (evt != SUITE_NAME) return ;

DBG_EVS("CLIENT::RECV    <- " + llList2CSV([evt , test_n , unused])) ;

    integer is_valid_test_n = test_n >= 0 && test_n < N_FIXTURES ;
    integer offset_idx      = N_PARAMS * test_n ;

    if (is_valid_test_n)
    {
      //string  request_json  = llList2Json(JSON_OBJECT , [ "client" , json ]) ;
      string  request_json  = llList2String (FIXTURES , offset_idx + REQUEST_IDX    ) ;
      string  response_json = llList2String (FIXTURES , offset_idx + RESPONSE_IDX   ) ;
      integer status        = llList2Integer(FIXTURES , offset_idx + STATUS_IDX     ) ;
      string  description   = llList2String (FIXTURES , offset_idx + DESCRIPTION_IDX) ;

      sendLinkMsg(REQUEST_IDX     , request_json  ) ;
      sendLinkMsg(RESPONSE_IDX    , response_json ) ;
      sendLinkMsg(STATUS_IDX      , (string)status) ;
      sendLinkMsg(DESCRIPTION_IDX , description   ) ;
      sendLinkMsg(ENDPOINT_IDX    , RESOURCE_PATH ) ;
    }
    else state default ;
  }
}
